#ifndef WALLE_BASE_DETAIL_PLATFORM_H_
#define WALLE_BASE_DETAIL_PLATFORM_H_


// Cygwin
// This is a pseudo-platform which will be defined along with PLATFORM_LINUX when
// using the Cygwin build environment.
#if defined(__CYGWIN__)
	#define PLATFORM_CYGWIN 1
	#define PLATFORM_DESKTOP 1
#endif

// MinGW
// This is a pseudo-platform which will be defined along with PLATFORM_WINDOWS when
// using the MinGW Windows build environment.
#if defined(__MINGW32__) || defined(__MINGW64__)
	#define PLATFORM_MINGW 1
	#define PLATFORM_DESKTOP 1
#endif

#if   defined(PLATFORM_LRB) || defined(__LRB__) || (defined(__EDG__) && defined(__ICC) && defined(__x86_64__))
	#undef  PLATFORM_LRB
	#define PLATFORM_LRB         1
	#define PLATFORM_NAME        "Larrabee"
	#define PLATFORM_DESCRIPTION "Larrabee on LRB1"
	#define PROCESSOR_X86_64 1
	#if defined(BYTE_ORDER) && (BYTE_ORDER == 4321)
		#define SYSTEM_BIG_ENDIAN 1
	#else
		#define SYSTEM_LITTLE_ENDIAN 1
	#endif
	#define PROCESSOR_LRB 1
	#define PROCESSOR_LRB1 1       // Larrabee version 1
	#define ASM_STYLE_ATT 1        // Both types of asm style
	#define ASM_STYLE_INTEL 1      // are supported.
	#define PLATFORM_DESKTOP 1

// Android (Google phone OS)
#elif defined(PLATFORM_ANDROID) || defined(__ANDROID__)
	#undef  PLATFORM_ANDROID
	#define PLATFORM_ANDROID 1
	#define PLATFORM_LINUX 1
	#define PLATFORM_UNIX 1
	#define PLATFORM_POSIX 1
	#define PLATFORM_NAME "Android"
	#define ASM_STYLE_ATT 1
	#if defined(__arm__)
		#define ABI_ARM_LINUX 1  // a.k.a. "ARM eabi"
		#define PROCESSOR_ARM32 1
		#define PLATFORM_DESCRIPTION "Android on ARM"
	#elif defined(__i386__)
		#define PROCESSOR_X86 1
		#define PLATFORM_DESCRIPTION "Android on x86"
	#else
		#error Unknown processor
	#endif
	#if !defined(SYSTEM_BIG_ENDIAN) && !defined(SYSTEM_LITTLE_ENDIAN)
		#define SYSTEM_LITTLE_ENDIAN 1
	#endif
	#define PLATFORM_MOBILE 1

// Samsung SMART TV - a Linux-based smart TV
#elif defined(PLATFORM_SAMSUNG_TV)
	#undef  PLATFORM_SAMSUNG_TV
	#define PLATFORM_SAMSUNG_TV 1
	#define PLATFORM_LINUX 1
	#define PLATFORM_UNIX 1
	#define PLATFORM_POSIX 1
	#define PLATFORM_NAME "SamsungTV"
	#define PLATFORM_DESCRIPTION "Samsung SMART TV on ARM"
	#define ASM_STYLE_ATT 1
	#define SYSTEM_LITTLE_ENDIAN 1
	#define PROCESSOR_ARM32 1
	#define ABI_ARM_LINUX 1 // a.k.a. "ARM eabi"
	#define PROCESSOR_ARM7 1

#elif defined(__APPLE__) && __APPLE__
	#include <TargetConditionals.h>

	// Apple family of operating systems.
	#define PLATFORM_APPLE
	#define PLATFORM_POSIX 1

	// iPhone
	// TARGET_OS_IPHONE will be undefined on an unknown compiler, and will be defined on gcc.
	#if defined(PLATFORM_IPHONE) || defined(__IPHONE__) || (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) || (defined(TARGET_IPHONE_SIMULATOR) && TARGET_IPHONE_SIMULATOR)
		#undef  PLATFORM_IPHONE
		#define PLATFORM_IPHONE 1
		#define PLATFORM_NAME "iPhone"
		#define ASM_STYLE_ATT 1
		#define POSIX_THREADS_AVAILABLE 1
		#if defined(__arm__)
			#define ABI_ARM_APPLE 1
			#define PROCESSOR_ARM32 1
			#define SYSTEM_LITTLE_ENDIAN 1
			#define PLATFORM_DESCRIPTION "iPhone on ARM"
		#elif defined(__aarch64__) || defined(__AARCH64)
			#define ABI_ARM64_APPLE 1
			#define PROCESSOR_ARM64 1
			#define SYSTEM_LITTLE_ENDIAN 1
			#define PLATFORM_DESCRIPTION "iPhone on ARM64"
		#elif defined(__i386__)
			#define PLATFORM_IPHONE_SIMULATOR 1
			#define PROCESSOR_X86 1
			#define SYSTEM_LITTLE_ENDIAN 1
			#define PLATFORM_DESCRIPTION "iPhone simulator on x86"
		#elif defined(__x86_64) || defined(__amd64)
			#define PROCESSOR_X86_64 1
			#define SYSTEM_LITTLE_ENDIAN 1
			#define PLATFORM_DESCRIPTION "iPhone simulator on x64"
		#else
			#error Unknown processor
		#endif
		#define PLATFORM_MOBILE 1

	// Macintosh OSX
	// TARGET_OS_MAC is defined by the Metrowerks and older AppleC compilers.
	// Howerver, TARGET_OS_MAC is defined to be 1 in all cases.
	// __i386__ and __intel__ are defined by the GCC compiler.
	// __dest_os is defined by the Metrowerks compiler.
	// __MACH__ is defined by the Metrowerks and GCC compilers.
	// powerc and __powerc are defined by the Metrowerks and GCC compilers.
	#elif defined(PLATFORM_OSX) || defined(__MACH__) || (defined(__MSL__) && (__dest_os == __mac_os_x))
		#undef  PLATFORM_OSX
		#define PLATFORM_OSX 1
		#define PLATFORM_UNIX 1
		#define PLATFORM_POSIX 1
	  //#define PLATFORM_BSD 1           We don't currently define this. OSX has some BSD history but a lot of the API is different.
		#define PLATFORM_NAME "OSX"
		#if defined(__i386__) || defined(__intel__)
			#define PROCESSOR_X86 1
			#define SYSTEM_LITTLE_ENDIAN 1
			#define PLATFORM_DESCRIPTION "OSX on x86"
		#elif defined(__x86_64) || defined(__amd64)
			#define PROCESSOR_X86_64 1
			#define SYSTEM_LITTLE_ENDIAN 1
			#define PLATFORM_DESCRIPTION "OSX on x64"
		#elif defined(__arm__)
			#define ABI_ARM_APPLE 1
			#define PROCESSOR_ARM32 1
			#define SYSTEM_LITTLE_ENDIAN 1
			#define PLATFORM_DESCRIPTION "OSX on ARM"
		#elif defined(__aarch64__) || defined(__AARCH64)
			#define ABI_ARM64_APPLE 1
			#define PROCESSOR_ARM64 1
			#define SYSTEM_LITTLE_ENDIAN 1
			#define PLATFORM_DESCRIPTION "OSX on ARM64"
		#elif defined(__POWERPC64__) || defined(__powerpc64__)
			#define PROCESSOR_POWERPC 1
			#define CS_UNDEFINED_STRING 1
			#define SYSTEM_BIG_ENDIAN 1
			#define PLATFORM_DESCRIPTION "OSX on PowerPC 64"
		#elif defined(__POWERPC__) || defined(__powerpc__)
			#define PROCESSOR_POWERPC 1
			#define PROCESSOR_POWERPC_32 1
			#define SYSTEM_BIG_ENDIAN 1
			#define PLATFORM_DESCRIPTION "OSX on PowerPC"
		#else
			#error Unknown processor
		#endif
		#if defined(__GNUC__)
			#define ASM_STYLE_ATT 1
		#else
			#define ASM_STYLE_MOTOROLA 1
		#endif
		#define PLATFORM_DESKTOP 1
	#else
		#error Unknown Apple Platform
	#endif

// Linux
// __linux and __linux__ are defined by the GCC and Borland compiler.
// __i386__ and __intel__ are defined by the GCC compiler.
// __i386__ is defined by the Metrowerks compiler.
// _M_IX86 is defined by the Borland compiler.
// __sparc__ is defined by the GCC compiler.
// __powerpc__ is defined by the GCC compiler.
#elif defined(PLATFORM_LINUX) || (defined(__linux) || defined(__linux__))
	#undef  PLATFORM_LINUX
	#define PLATFORM_LINUX 1
	#define PLATFORM_UNIX 1
	#define PLATFORM_POSIX 1
	#define PLATFORM_NAME "Linux"
	#if defined(__i386__) || defined(__intel__) || defined(_M_IX86)
		#define PROCESSOR_X86 1
		#define SYSTEM_LITTLE_ENDIAN 1
		#define PLATFORM_DESCRIPTION "Linux on x86"
	#elif defined(__x86_64__)
		#define PROCESSOR_X86_64 1
		#define SYSTEM_LITTLE_ENDIAN 1
		#define PLATFORM_DESCRIPTION "Linux on x64"
	#elif defined(__powerpc64__)
		#define PROCESSOR_POWERPC 1
		#define CS_UNDEFINED_STRING 1
		#define SYSTEM_BIG_ENDIAN 1
		#define PLATFORM_DESCRIPTION "Linux on PowerPC 64"
	#elif defined(__powerpc__)
		#define PROCESSOR_POWERPC 1
		#define PROCESSOR_POWERPC_32 1
		#define SYSTEM_BIG_ENDIAN 1
		#define PLATFORM_DESCRIPTION "Linux on PowerPC"
	#else
		#error Unknown processor
		#error Unknown endianness
	#endif
	#if defined(__GNUC__)
		#define ASM_STYLE_ATT 1
	#endif
	#define PLATFORM_DESKTOP 1


#elif defined(PLATFORM_BSD) || (defined(__BSD__) || defined(__FreeBSD__))
	#undef  PLATFORM_BSD
	#define PLATFORM_BSD 1
	#define PLATFORM_UNIX 1
	#define PLATFORM_POSIX 1     // BSD's posix complaince is not identical to Linux's
	#define PLATFORM_NAME "BSD Unix"
	#if defined(__i386__) || defined(__intel__)
		#define PROCESSOR_X86 1
		#define SYSTEM_LITTLE_ENDIAN 1
		#define PLATFORM_DESCRIPTION "BSD on x86"
	#elif defined(__x86_64__)
		#define PROCESSOR_X86_64 1
		#define SYSTEM_LITTLE_ENDIAN 1
		#define PLATFORM_DESCRIPTION "BSD on x64"
	#elif defined(__powerpc64__)
		#define PROCESSOR_POWERPC 1
		#define CS_UNDEFINED_STRING 1
		#define SYSTEM_BIG_ENDIAN 1
		#define PLATFORM_DESCRIPTION "BSD on PowerPC 64"
	#elif defined(__powerpc__)
		#define PROCESSOR_POWERPC 1
		#define PROCESSOR_POWERPC_32 1
		#define SYSTEM_BIG_ENDIAN 1
		#define PLATFORM_DESCRIPTION "BSD on PowerPC"
	#else
		#error Unknown processor
		#error Unknown endianness
	#endif
	#if !defined(PLATFORM_FREEBSD) && defined(__FreeBSD__)
		#define PLATFORM_FREEBSD 1 // This is a variation of BSD.
	#endif
	#if defined(__GNUC__)
		#define ASM_STYLE_ATT 1
	#endif
	#define PLATFORM_DESKTOP 1


#elif defined(PLATFORM_WINDOWS_PHONE)
	#undef PLATFORM_WINDOWS_PHONE
	#define PLATFORM_WINDOWS_PHONE 1
	#define PLATFORM_NAME "Windows Phone"
	#if defined(_M_AMD64) || defined(_AMD64_) || defined(__x86_64__)
		#define PROCESSOR_X86_64 1
		#define SYSTEM_LITTLE_ENDIAN 1
		#define PLATFORM_DESCRIPTION "Windows Phone on x64"
	#elif defined(_M_IX86) || defined(_X86_)
		#define PROCESSOR_X86 1
		#define SYSTEM_LITTLE_ENDIAN 1
		#define PLATFORM_DESCRIPTION "Windows Phone on X86"
	#elif defined(_M_ARM)
		#define ABI_ARM_WINCE 1
		#define PROCESSOR_ARM32 1
		#define SYSTEM_LITTLE_ENDIAN 1
		#define PLATFORM_DESCRIPTION "Windows Phone on ARM"
	#else //Possibly other Windows Phone variants
		#error Unknown processor
		#error Unknown endianness
	#endif
	#define PLATFORM_MICROSOFT 1

	// WINAPI_FAMILY defines - mirrored from winapifamily.h
	#define WINAPI_FAMILY_APP         1
	#define WINAPI_FAMILY_DESKTOP_APP 2
	#define WINAPI_FAMILY_PHONE_APP   3

	#if defined(WINAPI_FAMILY)
		#include <winapifamily.h>
		#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
			#define WINAPI_FAMILY WINAPI_FAMILY_PHONE_APP
		#else
			#error Unsupported WINAPI_FAMILY for Windows Phone
		#endif
	#else
		#error WINAPI_FAMILY should always be defined on Windows Phone.
	#endif

	// Macro to determine if a partition is enabled.
	#define WINAPI_FAMILY_PARTITION(Partition)   (Partition)

	// Enable the appropriate partitions for the current family
	#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
	#   define WINAPI_PARTITION_CORE    1
	#   define WINAPI_PARTITION_PHONE   1
	#   define WINAPI_PARTITION_APP     1
	#else
	#   error Unsupported WINAPI_FAMILY for Windows Phone
	#endif


// Windows
// _WIN32 is defined by the VC++, Intel and GCC compilers.
// _WIN64 is defined by the VC++, Intel and GCC compilers.
// __WIN32__ is defined by the Borland compiler.
// __INTEL__ is defined by the Metrowerks compiler.
// _M_IX86, _M_AMD64 and _M_IA64 are defined by the VC++, Intel, and Borland compilers.
// _X86_, _AMD64_, and _IA64_ are defined by the Metrowerks compiler.
// _M_ARM is defined by the VC++ compiler.
#elif (defined(PLATFORM_WINDOWS) || (defined(_WIN32) || defined(__WIN32__) || defined(_WIN64))) && !defined(CS_UNDEFINED_STRING)
	#undef  PLATFORM_WINDOWS
	#define PLATFORM_WINDOWS 1
	#define PLATFORM_NAME "Windows"
	#ifdef _WIN64 // VC++ defines both _WIN32 and _WIN64 when compiling for Win64.
		#define PLATFORM_WIN64 1
	#else
		#define PLATFORM_WIN32 1
	#endif
	#if defined(_M_AMD64) || defined(_AMD64_) || defined(__x86_64__)
		#define PROCESSOR_X86_64 1
		#define SYSTEM_LITTLE_ENDIAN 1
		#define PLATFORM_DESCRIPTION "Windows on x64"
	#elif defined(_M_IX86) || defined(_X86_)
		#define PROCESSOR_X86 1
		#define SYSTEM_LITTLE_ENDIAN 1
		#define PLATFORM_DESCRIPTION "Windows on X86"
	#elif defined(_M_IA64) || defined(_IA64_)
		#define PROCESSOR_IA64 1
		#define SYSTEM_LITTLE_ENDIAN 1
		#define PLATFORM_DESCRIPTION "Windows on IA-64"
	#elif defined(_M_ARM)
		#define ABI_ARM_WINCE 1
		#define PROCESSOR_ARM32 1
		#define SYSTEM_LITTLE_ENDIAN 1
		#define PLATFORM_DESCRIPTION "Windows on ARM"
	#else //Possibly other Windows CE variants
		#error Unknown processor
		#error Unknown endianness
	#endif
	#if defined(__GNUC__)
		#define ASM_STYLE_ATT 1
	#elif defined(_MSC_VER) || defined(__BORLANDC__) || defined(__ICL)
		#define ASM_STYLE_INTEL 1
	#endif
	#define PLATFORM_DESKTOP 1
	#define PLATFORM_MICROSOFT 1

	// WINAPI_FAMILY defines to support Windows 8 Metro Apps - mirroring winapifamily.h in the Windows 8 SDK
	#define WINAPI_PARTITION_DESKTOP   0x00000001
	#define WINAPI_PARTITION_APP       0x00000002
	#define WINAPI_FAMILY_APP          WINAPI_PARTITION_APP
	#define WINAPI_FAMILY_DESKTOP_APP  (WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_APP)

	#if defined(WINAPI_FAMILY)
		#if defined(_MSC_VER)
			#pragma warning(push, 0)
		#endif
		#include <winapifamily.h>
		#if defined(_MSC_VER)
			#pragma warning(pop)
		#endif
		#if WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP
			#define WINAPI_FAMILY WINAPI_FAMILY_DESKTOP_APP
		#elif WINAPI_FAMILY == WINAPI_FAMILY_APP
			#define WINAPI_FAMILY WINAPI_FAMILY_APP
		#else
			#error Unsupported WINAPI_FAMILY
		#endif
	#else
		#define WINAPI_FAMILY WINAPI_FAMILY_DESKTOP_APP
	#endif

	#define WINAPI_FAMILY_PARTITION(Partition)   ((WINAPI_FAMILY & Partition) == Partition)

	// PLATFORM_WINRT
	// This is a subset of Windows which is used for tablets and the "Metro" (restricted) Windows user interface.
	// WinRT doesn't doesn't have access to the Windows "desktop" API, but WinRT can nevertheless run on 
	// desktop computers in addition to tablets. The Windows Phone API is a subset of WinRT and is not included
	// in it due to it being only a part of the API.
	#if (defined(PLATFORM_WINDOWS) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP))
		#define PLATFORM_WINRT 1 
	#endif

// Sun (Solaris)
// __SUNPRO_CC is defined by the Sun compiler.
// __sun is defined by the GCC compiler.
// __i386 is defined by the Sun and GCC compilers.
// __sparc is defined by the Sun and GCC compilers.
#else
	#error Unknown platform
	#error Unknown processor
	#error Unknown endianness
#endif

#ifndef PROCESSOR_ARM
	#if defined(PROCESSOR_ARM32) || defined(PROCESSOR_ARM64) || defined(PROCESSOR_ARM7)
		#define PROCESSOR_ARM
	#endif
#endif

// PLATFORM_PTR_SIZE
// Platform pointer size; same as sizeof(void*).
// This is not the same as sizeof(int), as int is usually 32 bits on
// even 64 bit platforms.
//
// _WIN64 is defined by Win64 compilers, such as VC++.
// _M_IA64 is defined by VC++ and Intel compilers for IA64 processors.
// __LP64__ is defined by HP compilers for the LP64 standard.
// _LP64 is defined by the GCC and Sun compilers for the LP64 standard.
// __ia64__ is defined by the GCC compiler for IA64 processors.
// __arch64__ is defined by the Sparc compiler for 64 bit processors.
// __mips64__ is defined by the GCC compiler for MIPS processors.
// __powerpc64__ is defined by the GCC compiler for PowerPC processors.
// __64BIT__ is defined by the AIX compiler for 64 bit processors.
// __sizeof_ptr is defined by the ARM compiler (armcc, armcpp).
//
#ifndef PLATFORM_PTR_SIZE
	#if defined(__WORDSIZE) // Defined by some variations of GCC.
		#define PLATFORM_PTR_SIZE ((__WORDSIZE) / 8)
	#elif defined(_WIN64) || defined(__LP64__) || defined(_LP64) || defined(_M_IA64) || defined(__ia64__) || defined(__arch64__) || defined(__aarch64__) || defined(__mips64__) || defined(__64BIT__) || defined(__Ptr_Is_64)
		#define PLATFORM_PTR_SIZE 8
	#elif defined(__CC_ARM) && (__sizeof_ptr == 8)
		#define PLATFORM_PTR_SIZE 8
	#else
		#define PLATFORM_PTR_SIZE 4
	#endif
#endif



// PLATFORM_WORD_SIZE
// This defines the size of a machine word. This will be the same as
// the size of registers on the machine but not necessarily the same
// as the size of pointers on the machine. A number of 64 bit platforms
// have 64 bit registers but 32 bit pointers.
//
#ifndef PLATFORM_WORD_SIZE
   #if (PLATFORM_PTR_SIZE == 8)
	  #define PLATFORM_WORD_SIZE 8
   #else
	  #define PLATFORM_WORD_SIZE PLATFORM_PTR_SIZE
   #endif
#endif

// PLATFORM_MIN_MALLOC_ALIGNMENT
// This defines the minimal alignment that the platform's malloc 
// implementation will return. This should be used when writing custom
// allocators to ensure that the alignment matches that of malloc
#ifndef PLATFORM_MIN_MALLOC_ALIGNMENT
	#if defined PLATFORM_APPLE
		#define PLATFORM_MIN_MALLOC_ALIGNMENT 16
	#else
		#define PLATFORM_MIN_MALLOC_ALIGNMENT (PLATFORM_PTR_SIZE * 2)
	#endif
#endif


// MISALIGNED_SUPPORT_LEVEL
// Specifies if the processor can read and write built-in types that aren't
// naturally aligned.
//    0 - not supported. Likely causes an exception.
//    1 - supported but slow.
//    2 - supported and fast.
//
#ifndef MISALIGNED_SUPPORT_LEVEL
	#if defined(PROCESSOR_X64) || defined(PROCESSOR_X86_64)
		#define MISALIGNED_SUPPORT_LEVEL 2
	#else
		#define MISALIGNED_SUPPORT_LEVEL 0
	#endif
#endif

// Macro to determine if a Windows API partition is enabled. Always false on non Microsoft platforms.
#if !defined(WINAPI_FAMILY_PARTITION)
	#define WINAPI_FAMILY_PARTITION(Partition) (0)
#endif


// CACHE_LINE_SIZE
// Specifies the cache line size broken down by compile target.
// This the expected best guess values for the targets that we can make at compilation time.

#ifndef CACHE_LINE_SIZE
	#if   defined(PROCESSOR_X86)      
		#define CACHE_LINE_SIZE 32    // This is the minimum possible value.
	#elif defined(PROCESSOR_X86_64)  
		#define CACHE_LINE_SIZE 64    // This is the minimum possible value
	#elif defined(PROCESSOR_ARM32)
		#define CACHE_LINE_SIZE 32    // This varies between implementations and is usually 32 or 64. 
	#elif defined(PROCESSOR_ARM64)
		#define CACHE_LINE_SIZE 64    // Cache line Cortex-A8  (64 bytes) http://shervinemami.info/armAssembly.html however this remains to be mostly an assumption at this stage
	#elif (PLATFORM_WORD_SIZE == 4)
		#define CACHE_LINE_SIZE 32    // This is the minimum possible value
	#else
		#define CACHE_LINE_SIZE 64    // This is the minimum possible value
	#endif
#endif


#endif // CONFIG_DETAIL_PLATFORM_H_









